/* eslint-disable array-callback-return */
import { storage } from './storage'
import { permissionCodes } from '@/routes/permission'
import config from '@/config'
const { setting } = config
export const clearNoNumLen = (str, len, ty) => {
    // 先把非数字的都替换掉，除了数字和.
    str = str.replace(/[^\d.]/g, '')
    if (ty) { // 只能输入数字
        str = str.replace(/[^\d]/g, '')
    }
    // 剔除多于的0
    str = str.replace(/^(0+)/, '0').replace(/^(0[1-9]+)/, str.slice(1))
    // 保证只有出现一个.而没有多个.
    str = str.replace(/\.{2,}/g, '.')
    // 必须保证第一个为数字而不是.
    str = str.replace(/^\./g, '')
    // 保证.只出现一次，而不能出现两次以上
    str = str.replace('.', '$#$').replace(/\./g, '')
        .replace('$#$', '.')
    // 只能输入两个小数
    str = str.replace(/^(\.)*(\d+)\.(\d\d).*$/, '$1$2.$3')
    if (str.indexOf('.') === -1) {
        str = str.slice(0, len)
    } else {
        str = str.slice(0, len + 3)
    }
    return str
}
/**
 * 设置动态路由
 * @param {*} router 本地路由
 * @param {*} newRouter 动态获取路由
 * @param {*} accessList 动态获取按钮权限
 * @return {*} menuList 新路由
 */
export const setRouterByRoles = (newRouter, accessList, dataList) => {
    let goodsMangmentMenu = []
    let roles = []
    /** zch-2021-09-07
     * 递归整合权限码
     * @param {*} roles 权限集合
     * @param {*} children 子元素
     * @returns 整合后的权限集合
     */
    const getRouteByTree = (roles, children) => {
        children.map(menu => {
            if (!roles.includes(menu.code)) {
                roles.push(menu.code)
                if (menu.children) {
                    getRouteByTree(roles, menu.children)
                }
            }
        })
        return roles
    }
    newRouter.map(val => {
        if (!roles.includes(val.code)) {
            roles.push(val.code)
        }
        // val.code.indexOf(
        // permissionCodes.user_center ||
        // permissionCodes.operation_center ||
        // permissionCodes.goods_center ||
        // permissionCodes.order_center) > -1 &&
        if (val.children && val.children.length) {
            goodsMangmentMenu = [...goodsMangmentMenu, ...val.children]
        }
    })
    roles = getRouteByTree(roles, goodsMangmentMenu)
    for (const key in accessList) {
        if (!roles.includes(key)) {
            roles.push(key)
        }
        accessList[key].map(item => {
            if (!roles.includes(item.code)) {
                roles.push(item.code)
            }
        })
    }
    for (const key in dataList) {
        if (!roles.includes(key)) {
            roles.push(key)
        }
        dataList[key].map(item => {
            if (!roles.includes(item.code)) {
                roles.push(item.code)
            }
        })
    }
    return { permissionCodes: roles }
}

/** 判断是否为IE9以上，不是则提示下载最新浏览器
 * @return Boolean
 */
export const isLowerIEVersion = () => {
    /* 取得浏览器的userAgent字符串 */
    let userAgent = navigator.userAgent
    /* 判断是否IE<11浏览器 */
    let isIE = userAgent.indexOf('compatible') > -1 && userAgent.indexOf('MSIE') > -1
    /* 判断是否IE的Edge浏览器 */
    let isEdge = userAgent.indexOf('Edge') > -1 && !isIE
    let isIE11 = userAgent.indexOf('Trident') > -1 && userAgent.indexOf('rv:11.0') > -1
    if (isIE) {
        let reIE = new RegExp('MSIE (\\d+\\.\\d+)')
        reIE.test(userAgent)
        let fIEVersion = parseFloat(RegExp['$1'])
        if (fIEVersion === 7) {
            return 7
        } else if (fIEVersion === 8) {
            return 8
        } else if (fIEVersion === 9) {
            return 9
        } else if (fIEVersion === 10) {
            return 10
        } else {
            return 6
        }
    } else if (isEdge) {
        return 'edge'
    } else if (isIE11) {
        return 11
    } else {
        return false
    }
}

/**
 * 切换全屏
 * @param {*} ele 全屏元素
 */
export const changeFullScreen = (ele) => {
    ele = ele || document.getElementById('root')
    function fullScreen (ele) {
        // 判断各种浏览器，找到正确的方法
        let requestMethod = ele.requestFullScreen || //W3C
            ele.webkitRequestFullScreen || //FireFox
            ele.mozRequestFullScreen || //Chrome等
            ele.msRequestFullScreen; //IE11
        if (requestMethod) {
            requestMethod.call(ele);
        } else if (typeof window.ActiveXObject !== "undefined") { //for Internet Explorer
            // eslint-disable-next-line no-undef
            let wscript = new ActiveXObject("WScript.Shell");
            if (wscript !== null) {
                wscript.SendKeys("{F11}");
            }
        }
    }
    function exitFullscreen () {
        // 判断各种浏览器，找到正确的方法
        let exitMethod = document.exitFullscreen || //W3C
            document.mozCancelFullScreen || //FireFox
            document.webkitExitFullscreen || //Chrome等
            document.webkitExitFullscreen; //IE11
        if (exitMethod) {
            exitMethod.call(document);
        } else if (typeof window.ActiveXObject !== "undefined") { //for Internet Explorer
            // eslint-disable-next-line no-undef
            let wscript = new ActiveXObject("WScript.Shell");
            if (wscript !== null) {
                wscript.SendKeys("{F11}");
            }
        }
    }
    isFullScreen() ? exitFullscreen() : fullScreen(ele)
}
export const isFullScreen = () => {
    return !!(
        document.fullscreen ||
        document.mozFullScreen ||
        document.webkitIsFullScreen ||
        document.webkitFullScreen ||
        document.msFullScreen
    );
}
/**
 * 更换主题样式
 * @param {*} themeConfig 默认主题配置
 * @returns Promise 修改后的主题配置
 */
export const initTheme = (themeConfig) => {
    let local = storage.get('themeConfig')
    themeConfig = themeConfig || local
    if (!themeConfig.theme) return Promise.resolve({ theme: { color: 'f8711a' } })
    let rootDom = document.querySelector(':root')
    const { primaryColor, hbgColor, /*secondColor*/ bgColor } = themeConfig.theme
    rootDom.style.setProperty('--primary-color', primaryColor)
    rootDom.style.setProperty('--header-text-color', !hbgColor.includes('fff') ? '#fff' : '#333')
    rootDom.style.setProperty('--text-color', bgColor.includes('fff') ? '#333' : '#ccc')
    rootDom.style.setProperty('--header-bg-color', hbgColor)
    rootDom.style.setProperty('--bg-color', bgColor)
    rootDom.style.setProperty('--bg-active-color', bgColor.includes('fff') ? '#fff' : 'rgba(0,0,0,0.5)')
    rootDom.style.setProperty('--text-light-color', bgColor.includes('fff') ? primaryColor : '#fff')
    return Promise.resolve(themeConfig)
}

// match router
export const matchRouteByTree = (routes, path, existRoute = false, currentRoute = {}) => {
    routes.map(menu => {
        if (path === menu.path) {
            existRoute = true
            currentRoute = menu
        }
        if (menu.routes) {
            let route = matchRouteByTree(menu.routes, path, existRoute, currentRoute)
            existRoute = route.existRoute
            currentRoute = route.currentRoute
        }
    })
    // console.log({ existRoute, currentRoute }, 'existRoute');
    return { existRoute, currentRoute }
}
/**
 * 递归实现树形结构
 * time: zch-2021-0916
 * @param {*} treeArray 源数据
 * @param {*} props 自定义的字段名称 { children: 'children', pId: 'pId', id: 'id' }
 * @returns 树形结构数据
 */
export const arrayToTree = (treeArray, props = { children: 'children', pId: 'pId', id: 'id' }) => {
    let r = [];
    let tmpMap = {};
    let { children, pId, id } = props
    for (let i = 0, l = treeArray.length; i < l; i++) {
        // 以每条数据的id作为obj的key值，数据作为value值存入到一个临时对象里面
        tmpMap[treeArray[i][id]] = treeArray[i]
    }
    for (let i = 0, l = treeArray.length; i < l; i++) {
        let key = tmpMap[treeArray[i][pId]];
        //循环每一条数据的pid，假如这个临时对象有这个key值，就代表这个key对应的数据有children，需要Push进去
        if (key) {
            if (!key[children]) {
                key[children] = [];
                key[children].push(treeArray[i])
            } else {
                let current = treeArray[i][id]
                let hasData = key[children].filter(v => v[id] === current)
                !hasData.length && key[children].push(treeArray[i])
            }
        } else {
            //如果没有这个Key值，那就代表没有父级,直接放在最外层
            r.push(treeArray[i])
        }
    }
    return r
}

/**
 * 查找节点的父元素
 * zch-20210929
 * @param {*} tree 树节点
 * @param {*} parentId 父节点id
 * @param {*} props 自定义的字段名称 { children: 'children', pId: 'pId', id: 'id' }
 * @returns 查找到的父节点集合
 */
export const findParentNodes = (tree, parentId, props = { children: 'nodes', pId: 'pid', id: 'id' }) => {
    // 返回数据集合
    let temp = [];
    const { children, pId, id } = props
    // 声明递归函数
    const fn = (arr, parentId, props) => {
        // 遍历树
        for (let i = 0; i < arr.length; i++) {
            let item = arr[i];
            if (item[id] === parentId) {
                // 查找到指定节点加入集合
                temp.unshift(item);
                // 查找其父节点
                fn(tree, item[pId], props);
                // 不必向下遍历，跳出循环
                break;
            } else {
                if (item[children] && item[children].length > 0) {
                    // 向下查找到id
                    fn(item[children], parentId, props);
                }
            }
        }
    };
    // 调用函数
    fn(tree, parentId, props);
    // 返回结果
    return temp;
}

/**
 * 拓展树结构元
 * @param {*} tree 树数据
 * @param {*} props 自定义字段名称 { children: 'children', pId: 'pId', id: 'id' }
 * @returns
 */
export const setTreeProps = (tree, props = () => ({}), newExpandedKeys = []) => {
    const { children, id } = { children: 'nodes', id: 'id' }
    tree.map((item, index) => {
        let params = { ...props(item, index) }
        for (const key in params) {
            item[key] = params[key]
        }
        newExpandedKeys.push(item[id])
        if (item[children] && item[children].length) {
            let res = setTreeProps(item[children], props, newExpandedKeys)
            newExpandedKeys = Array.from(new Set([...newExpandedKeys, ...res.newExpandedKeys]))
        }
    })
    // console.log(newExpandedKeys, tree, 'newExpandedKeys');
    return { newExpandedKeys, tree }
}

// 事件防抖函数
export const debounce = (func, wait, immediate) => {
    let timeout;
    return function () {
        let args = arguments;
        let later = function () {
            timeout = null;
            if (!immediate) func.apply(this, args);
        };
        let callNow = immediate && !timeout;
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
        if (callNow) func.apply(this, args);
    };
}

/**
 * 系统校验规则及提示
 */
export class ValidationRules {
    constructor(props) {
        this.options = { ...props }
    }
    /** 校验数字
     * @param {*} str 校验单数组字
     * @param {*} len 长度限制
     * @param {*} ty 只能输入数字
     * @param {*} num 输入的数字大于 num 则显示num
     * @param {*} iszero 为true 不能以0开头
    */
    filterNum (str, len, ty, num, iszero) {
        // 先把非数字的都替换掉，除了数字和.
        str = str.replace(/[^\d.]/g, '')
        if (ty) { // 只能输入数字
            str = str.replace(/[^\d]/g, '')
        }
        // 剔除多于的0
        str = str.replace(/^(0+)/, '0').replace(/^(0[1-9]+)/, str.slice(1))
        // 保证只有出现一个.而没有多个.
        str = str.replace(/\.{2,}/g, '.')
        // 必须保证第一个为数字而不是.
        str = str.replace(/^\./g, '')
        if (iszero) {
            // 必须保证第一个数字不为0
            str = str.replace(/^0/g, '')
        }
        // 保证.只出现一次，而不能出现两次以上
        str = str.replace('.', '$#$').replace(/\./g, '')
            .replace('$#$', '.')
        // 只能输入两个小数
        str = str.replace(/^(\.)*(\d+)\.(\d\d).*$/, '$1$2.$3')
        if (str.indexOf('.') === -1) {
            str = str.slice(0, len)
        } else {
            str = str.slice(0, len + 3)
        }
        if (num && str > num) {
            str = num
        }
        return str
    }
    // 验证信息
    message (value) {
        const { type, message, max = 200, limit = 9 } = this.options
        value = value || this.options.value
        let tipMsg = ``
        if (!value) return `${message || '内容'}不能为空`
        switch (type) {
            case 'text':
                tipMsg = `${message || '内容'}不能为空`
                break
            case 'account':
                tipMsg = this.validateAccount()
                break
            case 'chinese':
                if (!this.regular('chinese').test(value)) {
                    tipMsg = '请输入中文字符'
                }
                break
            case 'phone':
                if (!this.regular('phone').test(value)) {
                    tipMsg = '请输入正确的手机号码'
                }
                break
            case 'tel':
                if (!this.regular('tel').test(value)) {
                    tipMsg = '请输入正确的电话号码'
                }
                break
            case 'email':
                if (!this.regular('email').test(value)) {
                    tipMsg = '请输入正确的邮箱'
                }
                break
            case 'qq':
                if (!this.regular('qq').test(value)) {
                    tipMsg = '请输入正确的QQ号码'
                }
                break
            case 'password':
                if (!this.regular('password').test(value)) {
                    tipMsg = setting.message.password
                }
                break
            case 'stock':
                tipMsg = value.length > limit ? `请输入正确的${message || '库存数量'}，不超过${limit || 9}位` : ''
                break
            case 'cart':
                tipMsg = value > max ? `超过最大数量限制${max}件` : ''
                break
            case 'price':
                tipMsg = (
                    !/^\d+(\.\d{0,2})?$/.test(value) ||
                    /^0/g.test(value)) &&
                    `请输入正确的${message || '价格'}`
                break
            default:
                tipMsg = ``
                break
        }
        return tipMsg
    }
    validate (rule, value, callback) {
        if (callback) {
            if (this.message(value)) {
                callback(this.message())
            } else {
                callback()
            }
            return
        }
        if (this.message(value)) {
            return Promise.reject(this.message(value))
        }
        return Promise.resolve()
    }
    // 验证的值
    value () {
        let { type, value, max = 200, limit = 9 } = this.options
        value = value.toString()
        let inputValue = ``
        switch (type) {
            case 'text':
                inputValue = value.slice(0, max)
                break
            case 'account':
            case 'password':
                inputValue = value.replace(!this.regular(type), '')
                break
            case 'phone':
                limit = 11
                inputValue = value.slice(0, limit)
                break
            case 'tel':
                limit = 15
                inputValue = value.slice(0, limit)
                break
            case 'stock':
                inputValue = this.filterNum(value, limit, true)
                break
            case 'cart':
                limit = 3
                inputValue = this.filterNum(value, limit, true, max)
                break
            case 'price':
                inputValue = this.filterNum(value, limit, false, '', true)
                break
            default:
                break
        }
        // if (JSON.stringify(parseFloat(inputValue)) !== 'NaN') {
        //     inputValue = parseFloat(inputValue)
        // }
        return inputValue
    }
    // 验证账号
    validateAccount () {
        const { value, password, type, confirmPassword, login } = this.options
        if (value && !this.regular(type).test(value)) {
            return login ? '账号或密码错误' : setting.message.account
        }
        if (password !== confirmPassword) {
            return '新密码与确认密码输入不一致'
        }
    }
    // 正则集合
    regular (type, limit = { min: 2, max: 4 }) {
        switch (type) {
            case 'phone': // 手机号码
                return /^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/
            case 'chinese': // 中文字符
                return /^[\u4e00-\u9fa5]{1,5}$/gm
            case 'tel': // 座机号码
                return /^((0\d{2,3}-\d{7,8})|(1[3584]\d{9}))$/
            case 'email': // 电子邮箱
                return /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/
            case 'idCard': // 身份证号码
                return /^[1-9]\d{5}(19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/
            case 'qq': // QQ号码
                return /^[1-9][0-9]\d{4,9}$/
            case 'account': // 注册账号
                return /^[\u4e00-\u9fa5|a-zA-Z0-9_][\u4e00-\u9fa5|a-zA-Z0-9_]{1,30}$/
            case 'password': // 密码
                return /^(?![0-9]+$)(?![a-zA-Z]+$)(?![0-9A-Z]+$)(?![0-9a-z]+$)[0-9A-Za-z]{8,30}$/
            default:
                break
        }
    }
}

/**
 * 拼接查询字符串
 * @param {*} query 查询对象
 * @returns 拼接后的字符串
 */
export const parseQueryToString = (query) => {
    let queryStr = ''
    for (const key in query) {
        if (query[key]) {
            !queryStr.includes('?') && (queryStr += '?')
            queryStr += key + '=' + query[key]
        }
        queryStr += '&'
    }
    queryStr = queryStr.slice(0, queryStr.length - 1)
    return queryStr
}